home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The PC-SIG Library 9
/
The PC-SIG Library on CD ROM - Ninth Edition.iso
/
501_600
/
DISK0579
/
DISK0579.ZIP
/
CHAP16.TXT
< prev
next >
Wrap
Text File
|
1989-12-01
|
14KB
|
354 lines
Chapter 16
VIRTUAL METHODS
Since we covered encapsulation and inheritance in the last
chapter, we are left with only virtual methods to complete the
major topics of object oriented programming. Virtual methods,
as they are called in TURBO Pascal, have several other names
in the literature to describe the same technique. This
technique is sometimes called run-time binding or late binding
referring to when the decision is made as to what method will
respond to the message. The use of virtual methods moves the
responsibility of selection from the client (the logic sending
the message) to the supplier (the methods responding to the
message). We will begin with a skeleton of a program without
a virtual method and add one to show the effect of adding a
virtual method.
WITHOUT A VIRTUAL METHOD
____________________________________________________________
The example program named VIRTUAL1.PAS will ================
be used as the starting point for the study VIRTUAL1.PAS
of virtual functions. We must state that ================
this program does not contain a virtual
function, it is only the starting point for
studying them.
The objects included here are very similar to the objects
describing vehicles which we were working with in the last
chapter. You will notice that all three objects contain a
method named Message in lines 11, 20, and 31. The Message
method will be the center of our study in the first three
example programs. It should be pointed out that the
constructors for the three objects are called in lines 98
through 100 even though a constructor call is still not
absolutely necessary in this case. We will have more to say
about the constructor calls during the next example program.
Compile and execute the program and you will find that even
though it is legal to pass the objects of type Car and Truck
to the method named Output_A_Message in lines 109 and 110, the
method that is called from line 86 is the method named Message
in the parent type Vehicle. This is probably no surprise to
you since we defined an object of type Vehicle as a formal
parameter of the method Output_A_Message. We need only one
small change and we will have a virtual procedure call.
Even though this program seems to do very little, it will be
the basis of our study of virtual methods so you should study
the code in detail.
Page 16-1
Virtual Methods
NOW TO MAKE IT A VIRTUAL METHOD
____________________________________________________________
Examine the example program named ================
VIRTUAL2.PAS, and you will find only one VIRTUAL2.PAS
small change in the code but a world of ================
difference in the way it executes.
The careful student will notice the addition of the reserved
word virtual in lines 13, 22, and 33. This makes the method
named Message a virtual method which operates a little
differently from the way it did in the last program. Once
again, we call the three constructors in lines 100 through 102
and this time the constructor calls are absolutely essential.
We will discuss why in a couple of paragraphs.
Once again we send a message to Output_A_Message three times
in lines 110 through 112 and line 88 is used to send a message
to the Message method. When we compile and execute this
program, we find that even though the method Output_A_Message
only uses the parent type Vehicle, the system calls the
correct procedure based on the type of the actual object
passed to this method. The system sends a message to the
objects of the correct type instead of to the parent type as
may be expected. It should be clear to you that the object
that is to receive the message is not known at compile time
but must be selected at run time when the object arrives at
the method Output_A_Message. This is known as late binding
since the type is not known until run time as opposed to early
binding where the type is known at compile time. Every
subprogram call in this entire tutorial, up to this point, has
been early binding.
You will note that even though the method Output_A_Message
only knows about the objects of type Vehicle, it has the
ability to pass through other types, provided of course that
they are descendant types of Vehicle. The method
Output_A_Message only passes the message through, it does not
do the selection. The selection is done by the objects
themselves which answer the messages passed to them. This
means that the sender does not know where the message will be
answered from, and it is up to the receiver to find that a
message is being sent its way and to respond to it. It is
often said that the supplier (the method doing the work) must
make the decision to answer the message, rather than the
client (the user of the work done). The burden is placed on
the supplier to do the right thing.
If a method is declared virtual, all methods of that name must
also be virtual including all ancestors and all descendants.
It is not possible to declare part of the methods of the same
name virtual and part standard. All parameter lists for all
virtual methods of the same name must also be identical since
Page 16-2
Virtual Methods
they must all be capable of being called by the same method
call.
ASSIGNING DESCENDANTS TO ANCESTORS?
____________________________________________________________
It is legal in any object oriented language to assign a
descendant object to an ancestor variable but the reverse is
not true. A vehicle, for example, can be used to define a
car, a truck, a bus, or any number of other kinds of vehicles
so it can be assigned any of those values. A car on the other
hand, is too specific to be used for the definition of
anything but a car, so it cannot have any other value assigned
to it. A vehicle is very general and can cover a wide range
of values, but a car is very specific and can therefore only
define a car.
WHY USE A CONSTRUCTOR?
____________________________________________________________
The constructor is absolutely required in this case because
of the way the authors of TURBO Pascal defined the use of
virtual functions. The constructor sets up a pointer to a
virtual method table (VMT) which is used to find the virtual
methods. If there is no pointer, the system jumps off to some
unknown location and tries to execute whatever happens to be
there and could do almost anything at that unknown and
undefined point in the code. So it is important to call a
constructor once for each object as is done here so the
pointer to the VMT can be initialized to the proper value.
If you make several objects of one type, it is not enough to
call a constructor for one object and copy that object into
each of the other objects. Each object must have its own
constructor call in order to prevent a system crash.
The strange looking code in line 6 tells the system to check
each call to a virtual function to see if the constructor has
been called. This slows the program down slightly but will
result in an error message if a virtual method is called prior
to its VMT being properly set up with a constructor call.
After a program is thoroughly tested, the code can be removed
from line 6 to speed up the program slightly by eliminating
the checks. Be warned however, that a call to a virtual
method without A VMT will probably result in the computer
hanging up.
Page 16-3
Virtual Methods
VIRTUALS AND POINTERS
____________________________________________________________
The example program named VIRTUAL3.PAS is ================
nearly identical to the last program except VIRTUAL3.PAS
that this program uses pointers to objects ================
instead of using the objects directly.
You will notice that once again, the methods named Message are
all defined as virtual and a pointer type is defined for each
object type. In lines 99 through 101, three pointers are
declared and memory is dynamically allocated on the heap for
the objects themselves. The objects are all sent a
constructor message to initialize the stored data within the
objects and to set up the VMT for each. The rest of the
program is nearly identical to the last program except that
Dispose procedures are called for each of the dynamically
allocated objects. The code used in line 6 of the last
program to force a check of each virtual method call has been
removed to illustrate that it doesn't have to be there if you
are sure a message is sent to a constructor once for each
object with a virtual method.
Compiling and executing this program will give the same result
as the last program indicating that it is perfectly legal to
use pointers to objects as well as the objects themselves.
AN ANCESTOR OBJECT
____________________________________________________________
The example program PERSON.PAS is not a ================
complete program at all but only an object PERSON.PAS
definition within a unit. This unit should ================
pose no problem for you to understand so we
will not say much except to point out that
the method named Display is a virtual method.
This example program, as well as the next two example
programs, have been carefully selected to illustrate the
proper way to package objects for use in a clear
understandable manner.
Compile this unit to disk in order to make it available for
use in the remainder of this chapter.
SOME DESCENDENT OBJECTS
____________________________________________________________
The example program named SUPERVSR.PAS is another unit which
contains three descendants of the previously defined object
Page 16-4
Virtual Methods
named Person. You will notice that each of ================
the objects have a method named Display which SUPERVSR.PAS
is virtual just as the same method in the ================
ancestor object was.
The interface for each object has been purposely kept very
simple in order to illustrate the use of objects. The
implementation has also been kept as simple as possible for
the same reason so the diligent student should have no trouble
in understanding this unit completely.
Once again, be sure to compile this unit to disk in order to
make it available for use in the next few example programs.
A COMPLETE EMPLOYEE PROGRAM
____________________________________________________________
Although the program named EMPLOYEE.PAS is a ================
very short program that does very little, it EMPLOYEE.PAS
is a complete program to handle a very small ================
amount of data about your employees.
You will notice that we declare an array of ten pointers to
the Person_ID object and one pointer to each of the three
descendant objects. In the main program we send a message to
the constructor for each of the array elements. Inspection
of the Person_ID.Init code will reveal that this
initialization does nothing. It is used to initialize the
pointer to the VMT for each object, so the message must be
sent. We then dynamically allocate six objects of assorted
descendant objects being careful to send a message to the
constructor for each object. This is done to generate a VMT
for each object as it is allocated. Finally, we send a
message to the first six objects pointed to by the array of
pointers instructing them to display their values.
When the program is compiled and executed, we find that the
virtual methods were called as explained in the last example
program. Even though only one kind of pointer was passed to
the Display method, three different messages were actually
displayed, each message being of the proper kind based on the
type of pointer used.
You will notice how clean and neat the main program is. It
is extremely easy to follow because all of the implementation
details have been moved to the objects themselves. Once the
objects are carefully defined and debugged, the main program
is usually a snap to write and debug.
Object oriented programming requires a whole new mindset over
the procedural methods you have been using but after you catch
on to the technique, you will find your programs much easier
Page 16-5
Virtual Methods
to debug and maintain. The one thing you should avoid is the
use of too many objects in your first program. It is best to
define a few simple objects for your first attempt at object
oriented programming and write the rest of the program using
standard procedural methods. Then as you gain experience, you
can begin using more and more objects until you finally write
a program that is essentially all objects. Of course, you
will find that you will always write at least part of your
program in a standard procedural format as was done in
EMPLOYEE.PAS in this chapter.
PROGRAMMING EXERCISE
____________________________________________________________
1. Add a new object type to SUPERVSR.PAS to define a
Consultant defining appropriate data fields for him, then
add a couple of Consultant type objects to EMPLOYEE.PAS
to use the new object type.
Page 16-6